package me.zhengjie.modules.system.service.impl

import me.zhengjie.common.utils.*
import me.zhengjie.common.utils.FileUtil.downloadExcel
import me.zhengjie.modules.system.domain.Province
import me.zhengjie.modules.system.repository.CityRepository
import me.zhengjie.modules.system.repository.ProvinceRepository
import me.zhengjie.modules.system.service.CityService
import me.zhengjie.modules.system.service.ProvinceService
import me.zhengjie.modules.system.service.dto.ProvinceDTO
import me.zhengjie.modules.system.service.dto.ProvinceQueryCriteria
import me.zhengjie.modules.system.service.mapper.ProvinceMapper
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Root
import jakarta.servlet.http.HttpServletResponse
import org.springframework.cache.annotation.CacheConfig
import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import java.io.IOException
import java.util.*
import java.util.function.Consumer

/**
 * @author kuki
 * @date 2022-07-21
 */
@Service
@CacheConfig(cacheNames = ["province"])
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = [Exception::class])
class ProvinceServiceImpl(
    private val cityRepository: CityRepository, private val cityService: CityService,
    private val provinceRepository: ProvinceRepository, private val provinceMapper: ProvinceMapper
) : ProvinceService {
    @Cacheable(key = "'queryall_criteria_pageable'")
    override fun queryAll(criteria: ProvinceQueryCriteria, pageable: Pageable?): Any? {
        val page =
            provinceRepository.findAll({ root: Root<Province?>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
                QueryHelp.getPredicate(
                    root,
                    criteria,
                    criteriaBuilder
                )
            }, pageable!!)

        return PageUtil.toPage(page.map { province: Province? -> provinceMapper.toDto(province) })
    }

    @Cacheable(key = "'queryall_criteria'")
    override fun queryAll(criteria: ProvinceQueryCriteria): List<ProvinceDTO?>? {
        return provinceMapper.toDto(provinceRepository.findAll { root: Root<Province?>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
            QueryHelp.getPredicate(
                root,
                criteria,
                criteriaBuilder
            )
        })
    }

    @Cacheable(key = "'getprovincesall'")
    override fun getProvincesAll(): List<Province?> {
        return provinceRepository.findAll()
    }

    @Cacheable(key = "'findbyid'+#p0")
    override fun findById(id: Int): ProvinceDTO? {
        val province = provinceRepository.findById(id).orElseGet { Province() }
        ValidationUtil.isNull(province!!.id, "Province", "id", id)
        return provinceMapper.toDto(province)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun create(resources: Province): ProvinceDTO? {
        return provinceMapper.toDto(provinceRepository.save(resources))
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun update(resources: Province) {
        val province = provinceRepository.findById(resources.id!!).orElseGet { Province() }
        ValidationUtil.isNull(province!!.id, "Province", "id", resources.id)
        province.copy(resources)
        provinceRepository.save(province)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun delete(id: Int) {
        provinceRepository.deleteById(id)
    }

    @Cacheable(key = "'provinceTree'")
    override fun getProvinceTree(provinces: List<Province?>): Any {
        val list: MutableList<Map<String, Any>> = LinkedList()
        provinces.forEach(
            Consumer { it: Province? ->
                if (it != null) {
                    val cityList = cityRepository.findByProvinceCode(it.provinceCode!!)
                    val map: MutableMap<String, Any> = HashMap()
                    map["id"] = it.id!!
                    map["provinceCode"] = it.provinceCode!!
                    map["label"] = it.name!!
                    map["labelChs"] = it.nameChs!!
                    map["labelEn"] = it.nameEn!!
                    if (cityList != null && cityList.size != 0) {
                        map["children"] = cityService.getCityTree(cityList)
                    }
                    list.add(map)
                }
            }
        )
        return list
    }

    @Throws(IOException::class)
    override fun download(all: List<ProvinceDTO>, response: HttpServletResponse?) {
        val list: MutableList<Map<String?, Any?>?> = ArrayList()
        for (province in all) {
            val map: MutableMap<String?, Any?> = LinkedHashMap()
            map["省份名称"] = province.name
            map["省份代码"] = province.provinceCode
            list.add(map)
        }
        downloadExcel(list, response!!)
    }
}